﻿using System;
using System.Globalization;

namespace EpiNEXT.Services.Validation.Functions
{
    public abstract class DateDiffBase : FunctionBase
    {
        public DateTime? StartDate { get; set; }
        public DateTime? EndDate { get; set; }

        public DateDiffBase()
            : base()
        {
        }

        public override object Execute(Record record)
        {
            object result = null;

            if (Parameters == null || Parameters.Count != 2)
            {
                return result;
            }

            object boxedParamDateStart = Parameters[0].GetValue(record);
            object boxedParamDateEnd = Parameters[1].GetValue(record);

            // one or both values are null; cannot evaluate (e.g. x + 5 = what? can't eval without knowing x)
            if (boxedParamDateStart == null || boxedParamDateEnd == null)
            {
                return result;
            }

            if (String.IsNullOrEmpty(boxedParamDateStart.ToString().Trim()) || String.IsNullOrEmpty(boxedParamDateEnd.ToString().Trim()))
            {
                return result;
            }

            SetDates(boxedParamDateStart, boxedParamDateEnd, record);

            if (StartDate.HasValue == false || EndDate.HasValue == false)
            {
                return result;
            }

            TimeSpan ts = EndDate.Value - StartDate.Value;
            return ts;
        }

        protected void SetDates(object boxedParamDateStart, object boxedParamDateEnd, Record record)
        {
            DataEntryInstrument form = record.Form;

            string startDateString = boxedParamDateStart.ToString();
            string endDateString = boxedParamDateEnd.ToString();

            if (boxedParamDateStart is double)
            {
                long startTicks = Convert.ToInt64(boxedParamDateStart) * 1000;
                StartDate = new DateTime(startTicks);
            }
            else if (Char.IsDigit(startDateString[0]) == true)
            {
                // detected a literal value; interpret as such
                StartDate = DateTime.Parse(startDateString, CultureInfo.InvariantCulture);
            }
            else
            {
                // detected a field value; pull from memory
                object fieldValue = record.GetFieldData(form.Fields[startDateString]);
                if (fieldValue == null)
                {
                    StartDate = null;
                }
                else
                {
                    StartDate = (DateTime)fieldValue;
                }
            }

            if (boxedParamDateEnd is double)
            {
                long endTicks = Convert.ToInt64(boxedParamDateEnd) * 1000;
                EndDate = new DateTime(endTicks);
            }
            else if (Char.IsDigit(endDateString[0]) == true)
            {
                // detected a literal value; interpret as such
                EndDate = DateTime.Parse(endDateString, CultureInfo.InvariantCulture);
            }
            else
            {
                // detected a field value; pull from memory
                object fieldValue = record.GetFieldData(form.Fields[endDateString]);
                if (fieldValue == null)
                {
                    EndDate = null; // no data, return null;
                }
                else
                {
                    EndDate = (DateTime)fieldValue;
                }
            }
        }
    }
}
